/*
 * clcomm.c
 *
 *  Created on: September 10, 2011
 *      Authors: Lane Aasen, Nikholas Gaffney, Michael Rosenberger, Dylan Swiggett
 */

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>
#include <ctype.h>

#define INBUFSIZE		2048			/*bytes allocated to the user input buffer*/
#define EBS				256				/*bytes allocated to the regex error buffer*/
#define CMDLEN			64				/*bytes allocated to the command*/
#define MAXFLAG			64				/*maximum number of flags*/
#define FLAGLEN			64				/*bytes allocated to each flag*/
#define MAXARG			512				/*maximum number of arguments*/
#define ARGLEN 			256 			/*bytes allocated to each argument*/
#define USER			"@Aasen: "

int parseflags(char* expflags[], int lenexpflags, char* allflags[], int lenallflags, char* valflags[], int lenvalflags);
int findmatches(char* string, regex_t regex, int numsubexpr, char* matches[], int matchsize, int maxmatches);
int strcmpr(char* stra, char* strb);
int sarraycont(char* sarray[], int sarraylen, char* string);

int initclcomm() {	

	/*initialize and compile regexes*/
	/*currently does *not* check for compilation errors for the sake of brevity*/
	regex_t commandRgx;
	int commandRgxS = regcomp(&commandRgx, "(^[a-z]+)", REG_EXTENDED);

	regex_t flagRgx;
	int flagRgxS = regcomp(&flagRgx, " -([a-zA-Z0-9]+)", REG_EXTENDED);

	regex_t argRgx;
	int argRgxS = regcomp(&argRgx, " ([a-zA-Z0-9.]+)", REG_EXTENDED);

	/*get user userinput, parse and call appropriate command function*/
	int run = 1;
	while(run) {
		/*display prompt text and flush stdout*/
		fputs(USER, stdout);
		fflush(stdout);
		
		char* userinput = malloc(INBUFSIZE);
		fgets(userinput, INBUFSIZE, stdin);
		
/*		printf("text = \"%s\" ... ", userinput);*/
    
		char* command[1];    	
    	int numcommands = findmatches(userinput, commandRgx, 2, command, CMDLEN, 1);
    	printf("command: \"%s\"", command[0]);
    	
   		char* flags[MAXFLAG];
   		int numflags = findmatches(userinput, flagRgx, 2, flags, FLAGLEN, MAXFLAG);
		int i; for(i = 0; i < numflags; i++) printf(" -\"%s\"", flags[i]);

    	char* args[MAXARG];
    	int numargs = findmatches(userinput, argRgx, 2, args, ARGLEN, MAXARG);
		int j; for(j = 0; j < numargs; j++) printf(" (%s)", args[j]);
		printf("\n");

    	/*send flags and args to the function referenced by command*/
    	if(strcmp(command[0], "exit") == 0) { run = 0; }
   		else if(strcmp(command[0], "t") == 0) { }
   		else {
   			printf("%s: command not found\n", command[0]);
   		}    	
	}
	return 0;
}

/*takes in an array of expected flags (expflags) and an array of all flags (allflags)*/
/*then stores the flags that appear in expflags and allflags in a repository of valid flags (valflags)*/
/*the respective lengths of each array are passed in; including valflags (to avoid buffer overflow)*/
/*the number of valid flags is returned*/
int parseflags(char* expflags[], int lenexpflags, char* allflags[], int lenallflags, char* valflags[], int lenvalflags) {
	int numvalflags; /*number of valid flags (different from lenvalflags, which is the maxiumum number of flags)*/
	
	int i; for(i = 0; i < lenallflags; i++) {
		int j; for(j = 0; j < lenexpflags; j++) 
			if(strcmp(allflags[i], expflags[j]) == 0) 
				if(!sarraycont(valflags, numvalflags, allflags[i])) 
					strcpy(valflags[numvalflags++], allflags[i]);
	}
					
	return numvalflags;
}

/*finds all expressions that match regex in string up to maxmatches (inclusive)*/
/*returns number of matches or -1 for buffer overflow*/
/*only works for regexes with one subexpression*/
int findmatches(char* string, regex_t regex, int numsubexpr, char* matches[], int matchsize, int maxmatches) {
	int nummatches = 0;
	regmatch_t* subexprmatches = malloc(sizeof(regmatch_t) * numsubexpr);
	
	int regexstate = regexec(&regex, string, numsubexpr, subexprmatches, 0);
	if(regexstate) return 0;
	while(!regexstate) {
		if(nummatches >= maxmatches) { return -1; 
		} else {
			matches[nummatches] = malloc(matchsize);
			memset(matches[nummatches], '\0', matchsize);
			strncpy(matches[nummatches], string + subexprmatches[1].rm_so, subexprmatches[1].rm_eo - subexprmatches[1].rm_so);
			nummatches++;
			string += subexprmatches[1].rm_eo;
		}
		regexstate = regexec(&regex, string, numsubexpr, subexprmatches, 0);
	} return nummatches;
}

/*returns true if stra and strb are equal*/
int strcmpr(char* stra, char* strb) {
	int i = 0;
	while(stra[i] == strb[i]) 
		if(stra[i++] == '\0') return 1;
	return 0;
}

/*returns true if the array of strings contains the specified string*/
int sarraycont(char* sarray[], int sarraylen, char* string) {
	int i = 0;
	while(i < sarraylen) 
		if(strcmpr(sarray[i++], string)) return 1;
	return 0;
}











